Skip to content

feat(api): update API spec from langfuse/langfuse d60e520#1694

Closed
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-d60e520
Closed

feat(api): update API spec from langfuse/langfuse d60e520#1694
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-d60e520

Conversation

@langfuse-bot

@langfuse-bot langfuse-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Greptile Summary

This auto-generated PR updates the Python SDK's scores API, promoting the v3 endpoint (GET /api/public/v3/scores) from the standalone scores_v3 sub-module into the main scores module, while moving the old v2 implementation to legacy/scores_v2 to preserve backward compatibility.

  • scores module promoted to v3: ScoresClient.get_many now calls /v3/scores with cursor-based pagination and a new set of filters (id, cursor, value_min, value_max, experiment_id, author_user_id); the response type is the new ScoreV3 discriminated union with a GetScoresMeta cursor envelope instead of the old page-based MetaResponse.
  • scores_v3 module removed: All types (BaseScoreV3, ScoreV3, ScoreSubject, etc.) are re-exported directly from langfuse.api.scores; the ScoreSubjectV3_* names are simplified to ScoreSubject_*.
  • Legacy v2 preserved under legacy/scores_v2: The old GetScoresResponse/GetScoresResponseData types and the full v2 parameter signature are intact and accessible via client.legacy.scores_v2, with deprecation notices in the docstrings.

Confidence Score: 4/5

Safe to merge; the change is auto-generated and the restructuring is clean. The only deviation is lazy imports placed inside property methods instead of at the module top.

The scores v3 promotion and legacy v2 preservation look correct. Types, discriminated unions, and export tables are internally consistent. The newly added ScoresV2Client property methods in legacy/client.py follow the same established lazy-import pattern already present throughout api/client.py, but those inline imports are new additions that violate the team's import placement rule.

langfuse/api/legacy/client.py — the two new scores_v2 property methods use inline imports that should be moved to the module top.

Sequence Diagram

sequenceDiagram
    participant User
    participant LangfuseAPI
    participant ScoresClient
    participant LegacyScoresV2Client
    participant Server

    Note over User,Server: New (v3) path — main scores module
    User->>LangfuseAPI: "client.scores.get_many(cursor=..., value_min=...)"
    LangfuseAPI->>ScoresClient: get_many(...)
    ScoresClient->>Server: GET /api/public/v3/scores
    Server-->>ScoresClient: "{data: ScoreV3[], meta: {limit, cursor}}"
    ScoresClient-->>User: GetScoresResponse (cursor-based)

    Note over User,Server: Legacy (v2) path — backward compat
    User->>LangfuseAPI: "client.legacy.scores_v2.get_many(page=..., user_id=...)"
    LangfuseAPI->>LegacyScoresV2Client: get_many(...)
    LegacyScoresV2Client->>Server: GET /api/public/v2/scores
    Server-->>LegacyScoresV2Client: "{data: GetScoresResponseData[], meta: {page, ...}}"
    LegacyScoresV2Client-->>User: GetScoresResponse (page-based, deprecated)
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
langfuse/api/legacy/client.py:63-70
**Imports inside property methods**

The new `scores_v2` property methods import `ScoresV2Client` and `AsyncScoresV2Client` at call time rather than at the top of the module. The project convention (established in `langfuse/api/client.py`) is to guard runtime imports inside properties with `# noqa: E402`, but the team rule asks for all imports to live at the module top level. The duplicate declarations already exist under `if typing.TYPE_CHECKING:`, so moving the runtime imports to the top (outside that guard) is the direct fix. The same pattern appears in the `AsyncLegacyClient.scores_v2` property on line 121.

Reviews (1): Last reviewed commit: "feat(api): update API spec from langfuse..." | Re-trigger Greptile

Context used:

  • Rule used - Move imports to the top of the module instead of p... (source)

Learned From
langfuse/langfuse-python#1387

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

@claude review

Comment on lines 27 to +32
def get_many(
self,
*,
page: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
user_id: typing.Optional[str] = None,
cursor: typing.Optional[str] = None,
fields: typing.Optional[str] = None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 The PR removes ScoresClient.get_by_id (sync and async) when switching /api/public/v2/scores to /api/public/v3/scores, but tests/e2e/test_core_sdk.py:158 (in test_create_session_score) still calls get_api().scores.get_by_id(score_id). This will raise AttributeError at runtime and is also a silent breaking change for any external consumer of the public langfuse.api.LangfuseAPI().scores.get_by_id() surface — the equivalent v2 method now lives at client.legacy.scores_v2.get_by_id(). Either update the test to use the new legacy path (or scores.get_many(id=score_id)) or restore a compat shim on scores.

Extended reasoning...

What the bug is

This PR migrates /api/public/v2/scores/api/public/v3/scores. The v3 API has no single-score lookup endpoint, so the generated ScoresClient.get_by_id / AsyncScoresClient.get_by_id methods (and their RawScoresClient counterparts) are deleted from langfuse/api/scores/client.py and langfuse/api/scores/raw_client.py. The replacement method has been moved to client.legacy.scores_v2.get_by_id (which still hits api/public/v2/scores/{score_id}).

Where it manifests

tests/e2e/test_core_sdk.py:158 (inside test_create_session_score, which is not skipped) still calls:

score = get_api().scores.get_by_id(score_id)

get_api() returns a _RetryingApiProxy that wraps langfuse.api.LangfuseAPI; its __getattr__ delegates .scores to the real ScoresClient, so .get_by_id resolves against the post-merge ScoresClient — which no longer defines that method.

Step-by-step proof

  1. After this PR, langfuse/api/scores/client.py defines ScoresClient with only __init__, with_raw_response, and get_many (see the diff hunk that deletes the def get_by_id(...) block; the synthesis-agent description also pins this).
  2. tests/support/utils.py builds get_api() by wrapping langfuse.api.LangfuseAPI() in _RetryingApiProxy, which forwards attribute access via getattr(self._target, name).
  3. test_create_session_score calls get_api().scores.get_by_id(score_id).
  4. Attribute resolution: _RetryingApiProxy.scoresLangfuseAPI.scores (lazy-initialised ScoresClient) → ScoresClient.get_by_id.
  5. Since ScoresClient no longer has get_by_id, Python raises AttributeError: ScoresClient object has no attribute get_by_id before the call even runs.
  6. The e2e test fails at runtime.

Why existing code does not prevent it

This is auto-generated by Fern, but the test in this repo references the generated surface directly and was not regenerated/edited in this PR. Any external user calling LangfuseAPI().scores.get_by_id(...) is in exactly the same position — the symbol simply vanishes without a deprecation shim.

Impact

  • The shipped e2e test will error out on every run after merge (test_create_session_score).
  • Public SDK breaking change: any downstream code that imported and used langfuse.api.LangfuseAPI().scores.get_by_id breaks the same way, with no deprecation period.

Fix

The simplest fixes (any one is sufficient):

  • Update the test to call the new legacy path:
    score = get_api().legacy.scores_v2.get_by_id(score_id)
  • Or use the v3 list endpoint and take the first result:
    score = get_api().scores.get_many(id=score_id).data[0]
  • Or restore a thin get_by_id alias on ScoresClient that proxies to legacy.scores_v2.get_by_id to preserve backwards compatibility for external callers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant